pub mod cmd;

use base::file::JsonFile;
use base::{
    base::{Base, VBase, VMap},
    client::Client,
    err, err_value, ok, throw_err, ECode, MapSv, RNull, Resp,
};
use bytes::Bytes;
use moka::future::Cache;
use serde_json::{json, Value};
use std::collections::HashSet;
use std::sync::Arc;
use std::time::Instant;
use tokio::sync::Mutex;
use tracing::{instrument, warn};
use warp::{
    reject::Rejection,
    reply::{Json, WithStatus},
};

pub type SvCache = Cache<String, Value>;
pub type Lock = Arc<Mutex<()>>;
pub type Sub<'a> = Option<&'a str>;
pub type SStr = HashSet<String>;
pub type VecSv = Vec<(String, Value)>;
pub type VecS = Vec<String>;

#[instrument(skip_all, name = "s")]
pub async fn do_cmd(
    data: Bytes,
    model: String,
    cmd: String,
    cache: SvCache,
    lock: Lock,
    client: &Client,
) -> Result<WithStatus<Json>, Rejection> {
    let val = match base::do_byte(data) {
        Ok(v) => v,
        Err(e) => {
            warn!("error val: {:?} - {:?}", &e, cmd);

            return Ok(base::ret_err(&e, None));
        }
    };

    let start = Instant::now();

    match cmd::doit(&val, &model, &cmd, cache, lock, client).await {
        Ok(v) => {
            let duration = start.elapsed();
            warn!(
                "dt: {:?} - end model: {:?} - cmd: {:?} - para: {:?}",
                duration, model, cmd, val
            );

            Ok(base::ret_ok(&v))
        }
        Err(e) => {
            let duration = start.elapsed();
            warn!(
                "dt: {:?} - error: {:?} - model: {:?} - cmd: {:?} - para: {:?}",
                duration, &e, model, cmd, val
            );

            Ok(base::ret_err(&e, None))
        }
    }
}

pub fn init_dir() {
    let p = get_cfg_root();
    let _ = JsonFile::make_dir(&p);
}

pub fn get_cfg_root() -> String {
    if cfg!(windows) {
        "./cfg".to_string()
    } else {
        "/files/cfg".to_string()
    }
}

pub fn get_cfg_file(sub: &str, k: &str) -> String {
    let path = get_cfg_root();

    let mut p = path.to_string();

    if !sub.is_empty() {
        p = format!("{p}/{sub}");
    }

    let _ = JsonFile::make_dir(&p);

    format!("{p}/{k}.json")
}
